

package com.bamboocloud.im.simpleConnector.simpleConnector;

import java.util.*;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bamboocloud.im.simpleConnector.simpleConnector.utils.PropertyUtil;
import com.bamboocloud.im.simpleConnector.simpleConnector.utils.TypeCastUtil;
import com.bamboocloud.im.simpleConnector.simpleConnector.utils.HttpUtil;
import org.identityconnectors.common.CollectionUtil;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.framework.common.exceptions.InvalidAttributeValueException;
import org.identityconnectors.framework.common.objects.*;
import org.identityconnectors.framework.common.objects.filter.FilterTranslator;
import org.identityconnectors.framework.spi.Configuration;
import org.identityconnectors.framework.spi.ConnectorClass;
import org.identityconnectors.framework.spi.Connector;
import org.identityconnectors.framework.spi.SearchResultsHandler;
import org.identityconnectors.framework.spi.operations.CreateOp;
import org.identityconnectors.framework.spi.operations.DeleteOp;
import org.identityconnectors.framework.spi.operations.SchemaOp;
import org.identityconnectors.framework.spi.operations.SearchOp;
import org.identityconnectors.framework.spi.operations.TestOp;
import org.identityconnectors.framework.spi.operations.UpdateOp;
import org.omg.CORBA.DynAnyPackage.Invalid;

/**
 * Main implementation of the simpleConnector Connector.
 *
 */
@ConnectorClass(
        displayNameKey = "simpleConnector.connector.display",
        configurationClass = simpleConnectorConfiguration.class)
public class simpleConnectorConnector implements Connector, CreateOp, DeleteOp, SchemaOp,
        SearchOp<String>, TestOp, UpdateOp {

    /**
     * Setup logging for the {@link simpleConnectorConnector}.
     */
    private static final Log logger = Log.getLog(simpleConnectorConnector.class);

    /**
     * Place holder for the {@link Configuration} passed into the init() method
     * {@link simpleConnectorConnector#init(org.identityconnectors.framework.spi.Configuration)}.
     */
    private simpleConnectorConfiguration configuration;

    private Schema schema = null;

    /**
     * Gets the Configuration context for this connector.
     *
     * @return The current {@link Configuration}
     */
    public Configuration getConfiguration() {
        return this.configuration;
    }

    /**
     * Callback method to receive the {@link Configuration}.
     *
     * @param configuration the new {@link Configuration}
     * @see org.identityconnectors.framework.spi.Connector#init(org.identityconnectors.framework.spi.Configuration)
     */
    public void init(final Configuration configuration) {
        this.configuration = (simpleConnectorConfiguration) configuration;
    }

    /**
     * Disposes of the {@link simpleConnectorConnector}'s resources.
     *
     * @see org.identityconnectors.framework.spi.Connector#dispose()
     */
    public void dispose() {
        configuration = null;
    }


    /******************
     * SPI Operations
     *
     * Implement the following operations using the contract and
     * description found in the Javadoc for these methods.
     ******************/



    /**
     * {@inheritDoc}
     */
    public Uid create(final ObjectClass objectClass, final Set<Attribute> createAttributes,
            final OperationOptions options) {
        simpleConnectorConnector.logger.info("===>同步创建");
        simpleConnectorConnector.logger.info("objectClass：{0}", new Object[] {objectClass});
        simpleConnectorConnector.logger.info("createAttributes：{0}", new Object[] {createAttributes});
        //设置bim请求参数
        final Map<String, String> bimRequestParams = HttpUtil.getBimRequestParams(this.configuration.getRemoteUser(), this.configuration.getPassword());
        //char [] testPwd = {'p','a','s','s','w','o','r','d'};
        //final Map<String, String> bimRequestParams = HttpUtil.getBimRequestParams("bimadmin", new GuardedString(testPwd));
        //判断是创建账户还是创建组织机构
        //创建账户时
        if(ObjectClass.ACCOUNT.equals(objectClass)){
            final Name name = AttributeUtil.getNameFromAttributes(createAttributes);
            if(name != null){
                try{
                    //设置请求参数
                    final String requestStr = HttpUtil.getAppRequestParams(createAttributes, bimRequestParams);
                    //发送请求
                    //String responseStr = HttpUtil.doPost("http://localhost:8089/UserCreateService", requestStr);
                    String responseStr = HttpUtil.doPost(this.configuration.getUserCreateUrl(), requestStr);
                    simpleConnectorConnector.logger.info("接口响应结果：{0}", responseStr);
                    if(responseStr != null && JSONObject.parseObject(responseStr).get("id") != null){
                        //返回接口传回的id
                        return new Uid(JSONObject.parseObject(responseStr).get("id").toString());
                    }
                    throw new InvalidAttributeValueException("接口调用失败：" + this.configuration.getUserCreateUrl());
                }
                catch(Exception e){
                    e.printStackTrace();
                    throw new InvalidAttributeValueException("接口调用失败：" + this.configuration.getUserCreateUrl());
                }
            }
            throw new InvalidAttributeValueException("Name attribute is required");
        }

        //创建机构时
        if("__ORGANIZATION__".equals(objectClass.getObjectClassValue())){
            final Name name = AttributeUtil.getNameFromAttributes(createAttributes);
            if(name != null){
                try{
                    //设置请求参数
                    final String requestStr = HttpUtil.getAppRequestParams(createAttributes, bimRequestParams);
                    //发送请求
                    //String responseStr = HttpUtil.doPost("http://localhost:8089/UserCreateService", requestStr);
                    String responseStr = HttpUtil.doPost(this.configuration.getOrgCreateUrl(), requestStr);
                    simpleConnectorConnector.logger.info("接口响应结果：{0}", responseStr);
                    if(responseStr != null && JSONObject.parseObject(responseStr).get("id") != null){
                        //返回接口传回的id
                        return new Uid(JSONObject.parseObject(responseStr).get("id").toString());
                    }
                    throw new InvalidAttributeValueException("接口调用失败：" + this.configuration.getOrgCreateUrl());
                }
                catch(Exception e){
                    e.printStackTrace();
                    throw new InvalidAttributeValueException("接口调用失败：" + this.configuration.getOrgCreateUrl());
                }
            }
            throw new InvalidAttributeValueException("Name attribute is required");
        }
        //创建不支持的对象类型时，抛出异常
        simpleConnectorConnector.logger.warn("Create of type {0} is not supported", new Object[] { this.configuration.getConnectorMessages().format(objectClass.getDisplayNameKey(), objectClass.getObjectClassValue(), new Object[0]) });
        throw new UnsupportedOperationException("Create of type " + objectClass.getObjectClassValue() + " is not supported");
    }

    /**
     * {@inheritDoc}
     */
    public void delete(final ObjectClass objectClass, final Uid uid, final OperationOptions options) {
        simpleConnectorConnector.logger.info("===>同步删除id:{0}", uid.getUidValue());
        simpleConnectorConnector.logger.info("objectClass：{0}", new Object[] {objectClass});
        //如果是删除账户
        if(ObjectClass.ACCOUNT.equals(objectClass)){
            final JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", uid.getUidValue());
            final Map<String, String> bimRequestParams = HttpUtil.getBimRequestParams(this.configuration.getRemoteUser(), this.configuration.getPassword());
            for(final String key : bimRequestParams.keySet()){
                jsonObject.put(key, bimRequestParams.get(key));
            }
            try{
                final String responseStr = HttpUtil.doPost(this.configuration.getUserDeleteUrl(), jsonObject.toJSONString());
                simpleConnectorConnector.logger.info("接口响应结果：{0}", responseStr);
                if(responseStr == null || JSONObject.parseObject(responseStr).getIntValue("resultCode") != 0){
                    throw new RuntimeException("delete account failed");
                }
            }catch (Exception e){
                e.printStackTrace();
                throw new RuntimeException("delete account failed");
            }
        }else if("__ORGANIZATION__".equals(objectClass.getObjectClassValue())){
            final JSONObject jsonObject = new JSONObject();
            jsonObject.put("id", uid.getUidValue());
            final Map<String, String> bimRequestParams = HttpUtil.getBimRequestParams(this.configuration.getRemoteUser(), this.configuration.getPassword());
            for(final String key : bimRequestParams.keySet()){
                jsonObject.put(key, bimRequestParams.get(key));
            }
            try{
                final String responesStr = HttpUtil.doPost(this.configuration.getOrgDeleteUrl(), jsonObject.toJSONString());
                simpleConnectorConnector.logger.info("接口响应结果：{0}", responesStr);
                if(responesStr == null || JSONObject.parseObject(responesStr).getIntValue("resultCode") != 0){
                    throw new RuntimeException("delete organization failed");
                }
            }catch (Exception e){
                e.printStackTrace();
                throw new RuntimeException("delete organization failed");
            }
        }else {
            //抛出对象类型不支持异常
            simpleConnectorConnector.logger.warn("Delete of type {0} is not supported", new Object[] { this.configuration.getConnectorMessages().format(objectClass.getDisplayNameKey(), objectClass.getObjectClassValue(), new Object[0]) });
            throw new UnsupportedOperationException("Delete of type" + objectClass.getObjectClassValue() + " is not supported");
        }
    }

    /**
     * {@inheritDoc}
     */
    public Schema schema() {
        if (null == schema) {
            simpleConnectorConnector.logger.info("==>同步对象属性");
            //设置请求参数
            JSONObject jsonObject = new JSONObject();
            final Map<String, String> bimRequestParams = HttpUtil.getBimRequestParams(this.configuration.getRemoteUser(), this.configuration.getPassword());
            for(String key : bimRequestParams.keySet()){
                jsonObject.put(key, bimRequestParams.get(key));
            }
            //发送请求,拿到下游应用响应的消息体
            simpleConnectorConnector.logger.info("请求接口地址：{0}", this.configuration.getSchemaServiceUrl());
            simpleConnectorConnector.logger.info("请求参数：{0}", jsonObject.toJSONString());
            String responseStr = HttpUtil.doPost(this.configuration.getSchemaServiceUrl(), jsonObject.toJSONString());
            //String responseStr = HttpUtil.doPost("http://localhost:8089/SchemaService", jsonObject.toJSONString());
            //打印接口响应信息
            simpleConnectorConnector.logger.info("接口：{0}，响应结果：{1}", new Object[]{this.configuration.getSchemaServiceUrl(), responseStr});
            //创建对象属性构建实例
            final SchemaBuilder builder = new SchemaBuilder(simpleConnectorConnector.class);
            //获取远程对象属性中的account对象的属性
            final String account = JSONObject.parseObject(responseStr).getString("account");
            //final String role = JSONObject.parseObject(responseStr).getString("role");
            //final String privilege = JSONObject.parseObject(responseStr).getString("privilege");
            // Account
            //构建用户的目标对象
            if(account != null && !account.equals("")){
                //打印属性
                System.out.println("Target Object - account："+ account);
                ObjectClassInfoBuilder accountInfoBuilder = new ObjectClassInfoBuilder();
                accountInfoBuilder.addAttributeInfo(Name.INFO);
                accountInfoBuilder.addAttributeInfo(OperationalAttributeInfos.PASSWORD);
                accountInfoBuilder.addAttributeInfo(PredefinedAttributeInfos.GROUPS);
                List<PropertyUtil> accountAAList = JSONObject.parseArray(account, PropertyUtil.class);
                //构建远程对象属性
                for(PropertyUtil accountInfo : accountAAList){
                    //打印属性信息
                    System.out.println("account schema：" + accountInfo.getName() + "-" + accountInfo.getType()
                            + "-" + accountInfo.isMultivalued() + "-" + accountInfo.isRequired());
                    //判断是否为必填项
                    if(accountInfo.isRequired()){
                        accountInfoBuilder.addAttributeInfo(AttributeInfoBuilder
                                .define(accountInfo.getName())
                                .setType(TypeCastUtil.getAttrTypeByName(accountInfo.getType()))
                                .setRequired(true).build());
                    }else{
                        //构建允许为空的属性
                        accountInfoBuilder.addAttributeInfo(AttributeInfoBuilder.build(
                                accountInfo.getName(), TypeCastUtil.getAttrTypeByName(accountInfo.getType())));
                    }
                }
                builder.defineObjectClass(accountInfoBuilder.build());
            }

            //Organization
            final String organization = JSONObject.parseObject(responseStr).getString("organization");
            if(organization != null && !organization.equals("")){
                //打印属性
                System.out.println("Target Object - account："+ account);
                ObjectClassInfoBuilder orgInfoBuilder = new ObjectClassInfoBuilder();
                orgInfoBuilder.setType("__ORGANIZATION__");
                orgInfoBuilder.addAttributeInfo(Name.INFO);
                orgInfoBuilder.addAttributeInfo(PredefinedAttributeInfos.DESCRIPTION);
                //将对象属性转为集合
                List<PropertyUtil> orgInfoList = JSONObject.parseArray(organization, PropertyUtil.class);
                //构建不为空的属性
                for(PropertyUtil orgInfo : orgInfoList){
                    if(orgInfo.isRequired()){
                        orgInfoBuilder.addAttributeInfo(AttributeInfoBuilder
                                .define(orgInfo.getName())
                                .setType(TypeCastUtil.getAttrTypeByName(orgInfo.getType()))
                                .setRequired(true).build());
                    }else{
                        //构建允许为空的属性(两个参数，一个为属性名称，一个为属性类型的类)
                        orgInfoBuilder.addAttributeInfo(AttributeInfoBuilder.build(
                                orgInfo.getName(),
                                TypeCastUtil.getAttrTypeByName(orgInfo.getType())));
                    }
                }
                // Only the CRUD operations
                builder.defineObjectClass(orgInfoBuilder.build(), CreateOp.class, SearchOp.class,
                        UpdateOp.class, DeleteOp.class);
            }else {
                simpleConnectorConnector.logger.info("接口返回结果：{0}", responseStr);
                throw new InvalidAttributeValueException("应用接口调用失败：" + this.configuration.getSchemaServiceUrl());
            }

            // Operation Options
            builder.defineOperationOption(OperationOptionInfoBuilder.buildAttributesToGet(),
                    SearchOp.class);

            // Support paged Search
            builder.defineOperationOption(OperationOptionInfoBuilder.buildPageSize(),
                    SearchOp.class);
            builder.defineOperationOption(OperationOptionInfoBuilder.buildPagedResultsCookie(),
                    SearchOp.class);

            // Support to execute operation with provided credentials
            builder.defineOperationOption(OperationOptionInfoBuilder.buildRunWithUser());
            builder.defineOperationOption(OperationOptionInfoBuilder.buildRunWithPassword());

            schema = builder.build();
        }
        return schema;
    }



    /**
     * {@inheritDoc}
     */
    public FilterTranslator<String> createFilterTranslator(ObjectClass objectClass,
            OperationOptions options) {
        return new simpleConnectorFilterTranslator();
    }

    /**
     * {@inheritDoc}
     */
    public void executeQuery(ObjectClass objectClass, String query, ResultsHandler handler,
            OperationOptions options) {
        final ConnectorObjectBuilder builder = new ConnectorObjectBuilder();
        builder.setUid("3f50eca0-f5e9-11e3-a3ac-0800200c9a66");
        builder.setName("Foo");
        builder.addAttribute(AttributeBuilder.buildEnabled(true));

        for (ConnectorObject connectorObject : CollectionUtil.newSet(builder.build())) {
            if (!handler.handle(connectorObject)) {
                // Stop iterating because the handler stopped processing
                break;
            }
        }
        if (options.getPageSize() != null && 0 < options.getPageSize()) {
            logger.info("Paged Search was requested");
            ((SearchResultsHandler) handler).handleResult(new SearchResult("0", 0));
        }
    }


    /**
     * {@inheritDoc}
     */
    public void test() {
        logger.ok("Test works well");
    }

    /**
     * {@inheritDoc}
     */
    public Uid update(ObjectClass objectClass, Uid uid, Set<Attribute> replaceAttributes,
            OperationOptions options) {
        simpleConnectorConnector.logger.info("===》同步更新");
        simpleConnectorConnector.logger.info("objectClass：{0}", new Object[]{objectClass});
        simpleConnectorConnector.logger.info("replaceAttribute：{0}", new Object[]{replaceAttributes});
        AttributesAccessor attributesAccessor = new AttributesAccessor(replaceAttributes);
        Name newName = attributesAccessor.getName();
        Uid uidAfterUpdate = uid;
        if (newName != null) {
            logger.info("Rename the object {0}:{1} to {2}", objectClass.getObjectClassValue(), uid
                    .getUidValue(), newName.getNameValue());
            uidAfterUpdate = new Uid(newName.getNameValue().toLowerCase(Locale.US));
        }
        //设置请求参数
        final Map<String, String> bimRequestParams = HttpUtil.getBimRequestParams(this.configuration.getRemoteUser(), this.configuration.getPassword());
        bimRequestParams.put("id", uid.getUidValue());
        //如果是更新账户
        if(ObjectClass.ACCOUNT.equals(objectClass)){
            try{
                final String requestJson = HttpUtil.getAppRequestParams(replaceAttributes, bimRequestParams);
                //发送请求
                final String result = HttpUtil.doPost(this.configuration.getUserUpdateUrl(), requestJson);
                simpleConnectorConnector.logger.info("接口响应结果：{0}", result);
                if(result == null || JSONObject.parseObject(result).getIntValue("resultCode") != 0){
                    throw new RuntimeException("update account failed");
                }
                return uidAfterUpdate;
            }catch (Exception e){
                e.printStackTrace();
                throw new RuntimeException("update account failed");
            }
        }

        //如果是更新机构
        if ("__ORGANIZATION__".equals(objectClass.getObjectClassValue())) {
            try{
                final String requestJson = HttpUtil.getAppRequestParams(replaceAttributes, bimRequestParams);
                //发送请求
                final String result = HttpUtil.doPost(this.configuration.getOrgUpdateUrl(), requestJson);
                simpleConnectorConnector.logger.info("接口响应结果：{0}", result);
                if(result == null || JSONObject.parseObject(result).getIntValue("resultCode") != 0){
                    throw new RuntimeException("update organization failed");
                }
                return uidAfterUpdate;
            }catch (Exception e){
                e.printStackTrace();
                throw new RuntimeException("update organization failed");
            }
        } else if (ObjectClass.GROUP.is(objectClass.getObjectClassValue())) {
            if (attributesAccessor.hasAttribute("members")) {
                throw new InvalidAttributeValueException(
                        "Requested to update a read only attribute");
            }
        } else {
            logger.warn("Update of type {0} is not supported", configuration.getConnectorMessages()
                    .format(objectClass.getDisplayNameKey(), objectClass.getObjectClassValue()));
            throw new UnsupportedOperationException("Update of type"
                    + objectClass.getObjectClassValue() + " is not supported");
        }
        return uidAfterUpdate;
    }

}
